package me.sealer.ssm.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.sealer.ssm.constant.Dict;
import me.sealer.ssm.constant.ErrorCodeConstant;
import me.sealer.ssm.constant.PermissionConstant;
import me.sealer.ssm.controller.dto.CommonResponse;
import me.sealer.ssm.controller.dto.DemoDownloadFileRequest;
import me.sealer.ssm.exception.SsmException;
import org.apache.commons.io.FileUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

/**
 * @author sealer
 * @date 2016/09/29
 */
@Slf4j
@RestController
@Api(tags = "文件上传下载相关api")
@RequestMapping("/fileOperations")
@RequiresPermissions(value = {PermissionConstant.FILE_MGMT})
public class FileController {
    @Value("${sealer.fileUploadPath}")
    private String prefixPath;

    /**
     * 通过流的方式自行处理上传文件
     *
     * @param file 将name=file控件得到的文件封装成CommonsMultipartFile 对象
     */
    @ApiOperation(value = "通过流的方式自行处理上传单文件")
    @PostMapping(value = "/singleFileUpload1", produces = MediaType.APPLICATION_JSON_VALUE)
    public CommonResponse singleFileUpload(MultipartFile file) {

        //获取输出流
        //获取输入流 MultipartFile 中可以直接得到文件的流
        int byteRead;
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(prefixPath + System.currentTimeMillis() + file.getOriginalFilename()));
             BufferedInputStream bis = new BufferedInputStream(file.getInputStream())) {
            while ((byteRead = bis.read()) != -1) {
                bos.write(byteRead);
            }
        } catch (IOException e) {
            throw new SsmException(e);
        }
        return new CommonResponse();
    }

    /**
     * 通过MultiPartFile.transferTo的方式处理上传文件
     *
     * @param file 将name=file控件得到的文件封装成MultipartFile 对象
     */
    @ApiOperation(value = "通过MultiPartFile#transferTo的方式处理上传单文件")
    @PostMapping(value = "/singleFileUpload2", produces = MediaType.APPLICATION_JSON_VALUE)
    public CommonResponse singleFileUploadWithFileTransferTo(MultipartFile file) {

        if (file == null) {
            throw new SsmException(ErrorCodeConstant.SYSTEM_UNKNOWN_ERROR, new Object[]{"上传文件为空"});
        }
        saveFile(file, prefixPath);
        return new CommonResponse();
    }

    /**
     * 采用file.transferTo 来处理上传的文件 多文件上传
     */
    @ApiOperation(value = "多文件上传")
    @PostMapping(value = "/multiFilesUpload1", produces = MediaType.APPLICATION_JSON_VALUE)
    public CommonResponse multiFilesUpload1(@RequestParam(Dict.FILES) MultipartFile[] files) {

        if (files == null || files.length <= 0) {
            throw new SsmException(ErrorCodeConstant.SYSTEM_UNKNOWN_ERROR, new Object[]{"上传文件列表为空"});
        }

        //循环获取file数组中得文件
        for (MultipartFile file : files) {
            //保存文件
            saveFile(file, prefixPath);
        }
        return new CommonResponse();
    }


    /**
     * 采用spring提供的方法处理上传文件
     *
     * @param request HttpServletRequest-MultipartHttpServletRequest
     * @return 上传是否成功结果返回
     */
    @ApiOperation(value = "采用spring提供的方法处理上传文件")
    @PostMapping(value = "/multiFilesUpload2", produces = MediaType.APPLICATION_JSON_VALUE)
    public CommonResponse springUpload(HttpServletRequest request) {
        //将当前上下文初始化给  CommonsMultipartResolver （多部分解析器）
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        //检查form中是否有enctype="multipart/form-data"
        if (multipartResolver.isMultipart(request)) {
            //将request变成多部分request
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
            //获取multiRequest 中所有的文件名
            Iterator<String> iterator = multiRequest.getFileNames();

            while (iterator.hasNext()) {
                //一次遍历所有文件
                List<MultipartFile> files = multiRequest.getFiles(iterator.next());
                if (files.size() == 0) {
                    throw new SsmException(ErrorCodeConstant.SYSTEM_UNKNOWN_ERROR, new Object[]{"上传文件列表为空"});
                }
                // 遍历多个文件
                for (MultipartFile file : files) {
                    if (file == null) {
                        throw new SsmException(ErrorCodeConstant.SYSTEM_UNKNOWN_ERROR, new Object[]{"上传文件为空"});
                    }
                    saveFile(file, prefixPath);
                }
            }
        }
        return new CommonResponse();
    }

    /**
     * 文件下载
     *
     * @param demoDownloadFileRequest 文件流方式下载demo请求数据
     * @return 文件流
     * @throws IOException 声明该方法可能会抛出的异常
     */
    @ApiOperation(value = "下载文件")
    @PostMapping(value = "/download")
    public ResponseEntity<byte[]> downloadFile(
            @Valid @RequestBody DemoDownloadFileRequest demoDownloadFileRequest
    ) throws IOException {
        String testParam1 = demoDownloadFileRequest.getTestParam1();
        log.info("demo download params - testParam1: " + testParam1);
        File file = new File("/home/sealer/ssm/files/nice.txt");

        HttpHeaders headers = new HttpHeaders();

        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", file.getName());

        return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
    }

    /**
     * 使用MultipartFile.transferTo保存文件
     *
     * @param multipartFile 待保存的文件
     * @param prefixPath    存储上传文件的路径前缀
     */
    public void saveFile(MultipartFile multipartFile, String prefixPath) {
        if (log.isDebugEnabled()) {
            log.debug("saved file's name：" + multipartFile.getOriginalFilename());
        }
        String path = prefixPath + System.currentTimeMillis() + multipartFile.getOriginalFilename();

        File newFile = new File(path);
        //通过MultipartFile的方法直接写文件（注意这个时候）
        try {
            multipartFile.transferTo(newFile);
        } catch (IOException e) {
            throw new SsmException(e);
        }
    }
}
